﻿using System;
using System.Buffers;
using System.Collections.Generic;
using System.Text;
using IOP.Protocols.MQTT.Package;
using IOP.Protocols.MQTT;
using IOP.Extension.Convert;
using System.Runtime.CompilerServices;

namespace IOP.Decoder.MQTT
{
    /// <summary>
    /// MQTT解码器
    /// </summary>
    public static class MQTTDecoder
    {
        /// <summary>
        /// 最大长度
        /// </summary>
        public const int MAXLENGTH = 2097152;

        /// <summary>
        /// 解码
        /// </summary>
        /// <param name="buffers"></param>
        public static IMQTTPackage Decode(ref ReadOnlySequence<byte> buffers)
        {
            IMQTTPackage package = null;
            if (buffers.IsEmpty) return package;
            SequencePosition position = buffers.Start;
            int offest = 0;
            ControlPacketType packetType = ControlPacketType.RESERVED;
            byte header = 0;
            var packageLength = 0;
            int multiplier = 1;
            bool foundFlag = false;

            try
            {
                #region FixHeader
                foreach (var segment in buffers)
                {
                    if (foundFlag) break;
                    foreach (var b in segment.Span)
                    {
                        if (offest == 0)
                        {
                            header = b;
                            packetType = (ControlPacketType)(b >> 4);
                            offest++;
                        }
                        else
                        {
                            packageLength += (b & 127) * multiplier;
                            multiplier *= 128;
                            offest++;
                            if (multiplier > MAXLENGTH) throw new Exception("Malformed Remaining Length");
                            if ((b & 128) == 0)
                            {
                                if (packageLength + 1 >= buffers.Length) return package;
                                position = buffers.GetPosition(offest);
                                foundFlag = true;
                                break;
                            }
                        }
                    }
                }
                switch (packetType)
                {
                    case ControlPacketType.RESERVED:
                        buffers = buffers.Slice(position);
                        throw new MQTTPackageException("Reserved is forbid to use");
                    case ControlPacketType.PINGREQ:
                        package = new PingreqPackage();
                        buffers = buffers.Slice(position);
                        break;
                    case ControlPacketType.PINGRESP:
                        package = new PingrespPackage();
                        buffers = buffers.Slice(position);
                        break;
                    case ControlPacketType.DISCONNECT:
                        package = new DisconnectPackage();
                        buffers = buffers.Slice(position);
                        break;
                }
                if (packageLength == 0) return package;
                #endregion
                switch (packetType)
                {
                    case ControlPacketType.CONNECT:
                        package = ConnectHandle(ref buffers, (ushort)packageLength, ref position);
                        break;
                    case ControlPacketType.CONNACK:
                        package = ConnackHandle(ref buffers, ref position);
                        break;
                    case ControlPacketType.PUBLISH:
                        package = PublishHandle(ref buffers, (ushort)packageLength, header, ref position);
                        break;
                    case ControlPacketType.PUBACK:
                    case ControlPacketType.PUBREC:
                    case ControlPacketType.PUBREL:
                    case ControlPacketType.PUBCOMP:
                        package = QosHandle(ref buffers, packetType, ref position);
                        break;
                    case ControlPacketType.SUBSCRIBE:
                        package = SubscribeHandle(ref buffers, (ushort)packageLength, ref position, buffers.GetPosition(packageLength, position));
                        break;
                    case ControlPacketType.SUBACK:
                        package = SubackHandle(ref buffers, (ushort)packageLength, ref position);
                        break;
                    case ControlPacketType.UNSUBSCRIBE:
                        package = UnsubscribeHandle(ref buffers, (ushort)packageLength, ref position, buffers.GetPosition(packageLength, position));
                        break;
                    case ControlPacketType.UNSUBACK:
                        package = UnsubackHandle(ref buffers, ref position);
                        break;
                    default:
                        throw new MQTTPackageException("ControlPacketType Error");
                }

                buffers = buffers.Slice(position);

                return package;
            }
            catch (Exception e)
            {
                throw e;
            }
        }
        /// <summary>
        /// 解码
        /// </summary>
        /// <param name="buffers"></param>
        public static IMQTTPackage Decode(ref byte[] buffers)
        {
            ReadOnlySpan<byte> datas = buffers;
            IMQTTPackage package = Decode(ref datas);
            buffers = datas.ToArray();
            return package;
        }
        /// <summary>
        /// 解码
        /// </summary>
        /// <param name="buffers"></param>
        public static IMQTTPackage Decode(ref ReadOnlySpan<byte> buffers)
        {
            int position = 0;
            IMQTTPackage package = null;
            if (buffers.IsEmpty) return package;
            ControlPacketType packetType = ControlPacketType.RESERVED;
            byte header = 0;
            var packageLength = 0;
            int multiplier = 1;
            try
            {
                #region FixHeader
                for (int i = position; i < buffers.Length; i++)
                {
                    if (i == 0)
                    {
                        header = buffers[i];
                        packetType = (ControlPacketType)(buffers[i] >> 4);
                    }
                    else
                    {
                        packageLength += (buffers[i] & 127) * multiplier;
                        multiplier *= 128;
                        if (multiplier > MAXLENGTH) throw new MQTTPackageException("Malformed Remaining Length");
                        if ((buffers[i] & 128) == 0)
                        {
                            if (packageLength + 1 >= buffers.Length) return package;
                            position += i + 1;
                            break;
                        }
                    }
                }
                switch (packetType)
                {
                    case ControlPacketType.RESERVED:
                        buffers = buffers.Slice(position);
                        throw new MQTTPackageException("Reserved is forbid to use");
                    case ControlPacketType.PINGREQ:
                        package = new PingreqPackage();
                        buffers = buffers.Slice(position);
                        break;
                    case ControlPacketType.PINGRESP:
                        package = new PingrespPackage();
                        buffers = buffers.Slice(position);
                        break;
                    case ControlPacketType.DISCONNECT:
                        package = new DisconnectPackage();
                        buffers = buffers.Slice(position);
                        break;
                }
                if (packageLength == 0) return package;
                #endregion
                switch (packetType)
                {
                    case ControlPacketType.CONNECT:
                        package = ConnectHandle(ref buffers, (ushort)packageLength, ref position);
                        break;
                    case ControlPacketType.CONNACK:
                        package = ConnackHandle(ref buffers, ref position);
                        break;
                    case ControlPacketType.PUBLISH:
                        package = PublishHandle(ref buffers, (ushort)packageLength, header, ref position);
                        break;
                    case ControlPacketType.PUBACK:
                    case ControlPacketType.PUBREC:
                    case ControlPacketType.PUBREL:
                    case ControlPacketType.PUBCOMP:
                        package = QosHandle(ref buffers, packetType, ref position);
                        break;
                    case ControlPacketType.SUBSCRIBE:
                        package = SubscribeHandle(ref buffers, (ushort)packageLength, ref position, position + packageLength);
                        break;
                    case ControlPacketType.SUBACK:
                        package = SubackHandle(ref buffers, (ushort)packageLength, ref position);
                        break;
                    case ControlPacketType.UNSUBSCRIBE:
                        package = UnsubscribeHandle(ref buffers, ref position, (ushort)packageLength, position + packageLength);
                        break;
                    case ControlPacketType.UNSUBACK:
                        package = UnsubackHandle(ref buffers, ref position);
                        break;
                    default:
                        throw new MQTTPackageException("ControlPacketType Error");
                }
                if (buffers.Length - position != 0)
                {
                    Span<byte> newBytes = new byte[buffers.Length - position];
                    buffers.Slice(position, buffers.Length - position).CopyTo(newBytes);
                    buffers = newBytes;
                }
                else buffers = new byte[0];
                return package;
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        /// <summary>
        /// 连接处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="length"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage ConnectHandle(ref ReadOnlySequence<byte> buffers, ushort length, ref SequencePosition position)
        {
            MQTTConnectOption option = new MQTTConnectOption();
            _ = MQTTUTF8ToString(ref buffers, ref position);

            int offest = 0;
            foreach (var seq in buffers.Slice(position, 2))
            {
                foreach (var b in seq.Span)
                {
                    if (offest == 0) option.ProtocolLevel = b;
                    else if (offest == 1)
                    {
                        option.UserNameFlag = ((b & 128) >> 7) == 1 ? true : false;
                        option.PasswordFlag = ((b & 64) >> 6) == 1 ? true : false;
                        option.WillRetain = ((b & 32) >> 5) == 1 ? true : false;
                        option.WillQoS = (QoSType)((b & 24) >> 3);
                        option.WillFlag = ((b & 4) >> 2) == 1 ? true : false;
                        option.CleanSession = ((b & 2) >> 1) == 1 ? true : false;
                    }
                    offest++;
                }
            }
            position = buffers.GetPosition(2, position);

            option.KeepAlive = GetLength(ref buffers, ref position);

            option.ClientIdentifier = MQTTUTF8ToString(ref buffers, ref position);

            if (option.WillFlag)
            {
                option.WillTopic = MQTTUTF8ToString(ref buffers, ref position);

                var messageLength = GetLength(ref buffers, ref position);
                var willMessage = buffers.Slice(position, messageLength);
                Span<byte> mesBytes = new byte[messageLength];
                willMessage.CopyTo(mesBytes);
                option.WillMessage = mesBytes.ToArray();
                position = buffers.GetPosition(messageLength, position);
            }

            if (option.UserNameFlag) option.UserName = MQTTUTF8ToString(ref buffers, ref position);

            if (option.PasswordFlag)
            {
                var passWordLength = GetLength(ref buffers, ref position);
                var password = buffers.Slice(position, passWordLength);
                Span<byte> pwdBytes = new byte[passWordLength];
                password.CopyTo(pwdBytes);
                option.Password = pwdBytes.ToArray();
                position = buffers.GetPosition(passWordLength, position);
            }
            ConnectPackage package = new ConnectPackage(option);

            return package;
        }
        /// <summary>
        /// 连接处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="length"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage ConnectHandle(ref ReadOnlySpan<byte> buffers, ushort length, ref int position)
        {
            MQTTConnectOption option = new MQTTConnectOption();
            _ = MQTTUTF8ToString(ref buffers, ref position);

            int offest = 0;
            for(int i = position; i< position + 2; i++)
            {
                if (offest == 0) option.ProtocolLevel = buffers[i];
                else if (offest == 1)
                {
                    option.UserNameFlag = ((buffers[i] & 128) >> 7) == 1 ? true : false;
                    option.PasswordFlag = ((buffers[i] & 64) >> 6) == 1 ? true : false;
                    option.WillRetain = ((buffers[i] & 32) >> 5) == 1 ? true : false;
                    option.WillQoS = (QoSType)((buffers[i] & 24) >> 3);
                    option.WillFlag = ((buffers[i] & 4) >> 2) == 1 ? true : false;
                    option.CleanSession = ((buffers[i] & 2) >> 1) == 1 ? true : false;
                }
                offest++;
            }
            position += 2;

            option.KeepAlive = GetLength(ref buffers, ref position);

            option.ClientIdentifier = MQTTUTF8ToString(ref buffers, ref position);

            if (option.WillFlag)
            {
                option.WillTopic = MQTTUTF8ToString(ref buffers, ref position);

                var messageLength = GetLength(ref buffers, ref position);
                Span<byte> message = new byte[messageLength];
                buffers.Slice(position, messageLength).CopyTo(message);
                option.WillMessage = message.ToArray();
                position += messageLength;
            }

            if (option.UserNameFlag) option.UserName = MQTTUTF8ToString(ref buffers, ref position);

            if (option.PasswordFlag)
            {
                var passwordLength = GetLength(ref buffers, ref position);
                Span<byte> passWord = new byte[passwordLength];
                buffers.Slice(position, passwordLength).CopyTo(passWord);
                option.Password = passWord.ToArray();
                position += passwordLength;
            }
            ConnectPackage package = new ConnectPackage(option);
            return package;
        }

        /// <summary>
        /// 连接回执处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage ConnackHandle(ref ReadOnlySequence<byte> buffers, ref SequencePosition position)
        {
            bool sessionPresent = false;
            ReturnCodeType returnCode = ReturnCodeType.ServerError;
            int offest = 0;
            foreach (var seq in buffers.Slice(position, 2))
            {
                foreach (var b in seq.Span)
                {
                    if (offest == 0) sessionPresent = b == 1 ? true : false;
                    else if (offest == 1) returnCode = (ReturnCodeType)b;
                    offest++;
                }
            }
            position = buffers.GetPosition(2, position);
            ConnackPackage package = new ConnackPackage(sessionPresent, returnCode);
            return package;
        }
        /// <summary>
        /// 连接回执处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage ConnackHandle(ref ReadOnlySpan<byte> buffers, ref int position)
        {
            bool sessionPresent = false;
            ReturnCodeType returnCode = ReturnCodeType.ServerError;
            int offest = 0;
            for (int i = position; i < position + 2; i++)
            {
                if (offest == 0) sessionPresent = buffers[i] == 1 ? true : false;
                else if (offest == 1) returnCode = (ReturnCodeType)buffers[i];
                offest++;
            }
            position += 2;
            ConnackPackage package = new ConnackPackage(sessionPresent, returnCode);
            return package;
        }

        /// <summary>
        /// 发布处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="position"></param>
        /// <param name="header"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage PublishHandle(ref ReadOnlySequence<byte> buffers, ushort length, byte header, ref SequencePosition position)
        {
            var dup = ((header & 8) >> 3) == 1 ? true : false;
            var retain = (header & 1) == 1 ? true : false;
            var qoS = (QoSType)((header & 6) >> 1);
            ushort packetId = 0;
            int sheader = 0;

            string topic = MQTTUTF8ToString(ref buffers, ref position);
            sheader += topic.Length + 2;

            if (qoS != QoSType.QoS0)
            {
                packetId = GetLength(ref buffers, ref position);
                sheader += 2;
            }

            var dataEndPosition = buffers.GetPosition(length - sheader, position);
            var dataSeq = buffers.Slice(position, dataEndPosition);
            Span<byte> datas = new byte[dataSeq.Length];
            int index = 0;
            foreach (var seq in dataSeq)
            {
                seq.Span.CopyTo(datas.Slice(index, seq.Span.Length));
                index += seq.Span.Length;
            }
            position = dataEndPosition;

            PublishPackage package = new PublishPackage(topic, packetId, datas.ToArray(), qoS, dup, retain);
            return package;
        }
        /// <summary>
        /// 发布处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="length"></param>
        /// <param name="header"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage PublishHandle(ref ReadOnlySpan<byte> buffers, ushort length, byte header, ref int position)
        {
            ReadOnlySpan<byte> datas = buffers;
            var dup = ((header & 8) >> 3) == 1 ? true : false;
            var retain = (header & 1) == 1 ? true : false;
            var qoS = (QoSType)((header & 6) >> 1);
            ushort packetId = 0;
            int sheader = 0;
            Span<byte> body = new byte[0];

            string topic = MQTTUTF8ToString(ref buffers, ref position);
            sheader += topic.Length + 2;

            if (qoS != QoSType.QoS0)
            {
                packetId = GetLength(ref datas, ref position);
                sheader += 2;
            }
            if (length - position > 0)
            {
                body = new byte[length - sheader];
                datas = datas.Slice(position, length - sheader);
                datas.CopyTo(body);
                position += (length - sheader);
            }

            PublishPackage package = new PublishPackage(topic, packetId, body.ToArray(), qoS, dup, retain);
            return package;
        }

        /// <summary>
        /// 发布确认处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="position"></param>
        /// <param name="packetType"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage QosHandle(ref ReadOnlySequence<byte> buffers, ControlPacketType packetType, ref SequencePosition position)
        {
            switch (packetType)
            {
                case ControlPacketType.PUBACK:
                    PubackPackage puback = new PubackPackage();
                    puback.PacketIdentifier = GetLength(ref buffers, ref position);
                    return puback;
                case ControlPacketType.PUBREC:
                    PubrecPackage pubrec = new PubrecPackage();
                    pubrec.PacketIdentifier = GetLength(ref buffers, ref position);
                    return pubrec;
                case ControlPacketType.PUBREL:
                    PubrelPackage pubrel = new PubrelPackage();
                    pubrel.PacketIdentifier = GetLength(ref buffers, ref position);
                    return pubrel;
                case ControlPacketType.PUBCOMP:
                    PubcompPackage pubcomp = new PubcompPackage();
                    pubcomp.PacketIdentifier = GetLength(ref buffers, ref position);
                    return pubcomp;
                default:
                    throw new Exception("Control Packet Type Error");
            }
        }
        /// <summary>
        /// 发布确认处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="packetType"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage QosHandle(ref ReadOnlySpan<byte> buffers, ControlPacketType packetType, ref int position)
        {
            switch (packetType)
            {
                case ControlPacketType.PUBACK:
                    PubackPackage puback = new PubackPackage();
                    puback.PacketIdentifier = GetLength(ref buffers, ref position);
                    return puback;
                case ControlPacketType.PUBREC:
                    PubrecPackage pubrec = new PubrecPackage();
                    pubrec.PacketIdentifier = GetLength(ref buffers, ref position);
                    return pubrec;
                case ControlPacketType.PUBREL:
                    PubrelPackage pubrel = new PubrelPackage();
                    pubrel.PacketIdentifier = GetLength(ref buffers, ref position);
                    return pubrel;
                case ControlPacketType.PUBCOMP:
                    PubcompPackage pubcomp = new PubcompPackage();
                    pubcomp.PacketIdentifier = GetLength(ref buffers, ref position);
                    return pubcomp;
                default:
                    throw new Exception("Control Packet Type Error");
            }
        }

        /// <summary>
        /// 订阅处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="length"></param>
        /// <param name="position"></param>
        /// <param name="endPosition"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage SubscribeHandle(ref ReadOnlySequence<byte> buffers, ushort length, ref SequencePosition position, SequencePosition endPosition)
        {
            var packetId = GetLength(ref buffers, ref position);
            List<TopicFilter> filters = new List<TopicFilter>();
            while (!position.Equals(endPosition))
            {
                TopicFilter topicFilter = new TopicFilter();
                topicFilter.FilterName = MQTTUTF8ToString(ref buffers, ref position);
                var qos = buffers.Slice(position, 1);
                topicFilter.RequestedQoS = (QoSType)qos.First.Span[0];
                filters.Add(topicFilter);
                position = buffers.GetPosition(1, position);
            }

            SubscribePackage package = new SubscribePackage(packetId, filters.ToArray());
            return package;
        }
        /// <summary>
        /// 订阅处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="length"></param>
        /// <param name="endPosition"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage SubscribeHandle(ref ReadOnlySpan<byte> buffers, ushort length, ref int position, int endPosition)
        {
            ReadOnlySpan<byte> bytes = buffers;
            var packetId = GetLength(ref bytes, ref position);
            List<TopicFilter> filters = new List<TopicFilter>();
            while (position != endPosition)
            {
                TopicFilter topicFilter = new TopicFilter();
                topicFilter.FilterName = MQTTUTF8ToString(ref buffers, ref position);
                var qos = buffers[position];
                position++;
                topicFilter.RequestedQoS = (QoSType)qos;
                filters.Add(topicFilter);
            }

            SubscribePackage package = new SubscribePackage(packetId, filters.ToArray());
            return package;
        }

        /// <summary>
        /// 订阅回执处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="length"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage SubackHandle(ref ReadOnlySequence<byte> buffers,ushort length, ref SequencePosition position)
        {
            var packetId = GetLength(ref buffers, ref position);

            SubackCode[] codes = new SubackCode[length - 2];
            int index = 0;
            foreach (var seq in buffers.Slice(position, length - 2))
                foreach (var b in seq.Span)
                    codes[index++] = (SubackCode)b;
            position = buffers.GetPosition(length - 2, position);
            SubackPackage package = new SubackPackage(packetId, codes);
            return package;
        }
        /// <summary>
        /// 订阅回执处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="length"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage SubackHandle(ref ReadOnlySpan<byte> buffers, ushort length, ref int position)
        {
            ReadOnlySpan<byte> bytes = buffers;
            var packetId = GetLength(ref bytes, ref position);
            SubackCode[] subacks = new SubackCode[length - 2];
            for (int i = 0;i < length - 2; i++)
            {
                subacks[i] = (SubackCode)buffers[position + i];
            }
            position = position + length - 2;

            SubackPackage package = new SubackPackage(packetId, subacks);
            return package;
        }

        /// <summary>
        /// 取消订阅处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="length"></param>
        /// <param name="position"></param>
        /// <param name="endPosition"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage UnsubscribeHandle(ref ReadOnlySequence<byte> buffers, ushort length, ref SequencePosition position, SequencePosition endPosition)
        {
            var packetId = GetLength(ref buffers, ref position);
            List<string> filters = new List<string>();
            while (!position.Equals(endPosition))
            {
                filters.Add(MQTTUTF8ToString(ref buffers, ref position));
            }

            UnsubscribePackage package = new UnsubscribePackage(packetId, filters.ToArray());
            return package;
        }
        /// <summary>
        /// 取消订阅处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="length"></param>
        /// <param name="endPosition"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage UnsubscribeHandle(ref ReadOnlySpan<byte> buffers, ref int position, ushort length, int endPosition)
        {
            ReadOnlySpan<byte> bytes = buffers;
            var packetId = GetLength(ref bytes, ref position);
            List<string> filters = new List<string>();
            while (position != endPosition)
            {
                filters.Add(MQTTUTF8ToString(ref buffers, ref position));
            }

            UnsubscribePackage package = new UnsubscribePackage(packetId, filters.ToArray());
            return package;
        }

        /// <summary>
        /// 取消订阅回执处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage UnsubackHandle(ref ReadOnlySequence<byte> buffers, ref SequencePosition position)
        {
            UnsubackPackage package = new UnsubackPackage();
            package.PacketIdentifier = GetLength(ref buffers, ref position);
            return package;
        }
        /// <summary>
        /// 取消订阅回执处理函数
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static IMQTTPackage UnsubackHandle(ref ReadOnlySpan<byte> buffers, ref int position)
        {
            UnsubackPackage package = new UnsubackPackage();
            ReadOnlySpan<byte> bytes = buffers;
            package.PacketIdentifier = GetLength(ref bytes, ref position);
            return package;
        }

        /// <summary>
        /// 获取MQTTUTF8编码字符串
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static string MQTTUTF8ToString(ref ReadOnlySequence<byte> buffers, ref SequencePosition position)
        {
            var length = GetLength(ref buffers, ref position);
            var result = GetUTF8String(buffers.Slice(position, length));
            position = buffers.GetPosition(length, position);
            return result;
        }
        /// <summary>
        /// 获取MQTTUTF8编码字符串
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static string MQTTUTF8ToString(ref ReadOnlySpan<byte> buffers, ref int position)
        {
            var length = GetLength(ref buffers, ref position);
            return GetUTF8String(ref buffers, ref position, length);
        }
        /// <summary>
        /// 获取MQTTUTF8编码字符串
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static string MQTTUTF8ToString(ref byte[] buffers, ref int position)
        {
            ReadOnlySpan<byte> bytes = buffers;
            return MQTTUTF8ToString(ref bytes, ref position);
        }

        /// <summary>
        /// 获取UTF8编码字符串
        /// </summary>
        /// <param name="buffers"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static string GetUTF8String(ReadOnlySequence<byte> buffers)
        {
            if (buffers.IsSingleSegment) return Encoding.UTF8.GetString(buffers.First.ToArray());
            else
            {
                return string.Create((int)buffers.Length, buffers, (span, sequence) =>
                {
                    foreach (var segment in sequence)
                    {
                        Encoding.UTF8.GetChars(segment.Span, span);
                        span = span.Slice(segment.Length);
                    }
                });
            }
        }
        /// <summary>
        /// 获取UTF8编码字符串
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="position"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static string GetUTF8String(ref ReadOnlySpan<byte> buffers, ref int position, int length)
        {
            if (length == 0) return "";
            ReadOnlySpan<byte> newBytes = buffers.Slice(position, length);
            position += length;
            return Encoding.UTF8.GetString(newBytes);
        }

        /// <summary>
        /// 获取长度
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static ushort GetLength(ref ReadOnlySequence<byte> buffers, ref SequencePosition position)
        {
            int index = 0;
            Span<byte> local = stackalloc byte[2];
            buffers.Slice(position, 2).CopyTo(local);
            ReadOnlySpan<byte> read = local;
            read.GetValueFromBytes(ref index, out ushort length);
            position = buffers.GetPosition(2, position);
            return length;
        }
        /// <summary>
        /// 获取长度
        /// </summary>
        /// <param name="buffers"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static ushort GetLength(ref ReadOnlySpan<byte> buffers, ref int position)
        {
            buffers.GetValueFromBytes(ref position, out ushort length);
            return length;
        }
    }
}
